﻿using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Microsoft.CSharp;
using XXF.BaseService.ServiceCenter.SystemRuntime;
using XXF.Common;
using System.IO;

namespace XXF.BaseService.ServiceCenter.Service.DynamicProxy
{
    /// <summary>
    /// 动态编译提供类
    /// </summary>
    public class DynamicCompilerProvider
    {
        /// <summary>
        /// （相同编译代码）动态编译程序集缓存
        /// </summary>
        private static Dictionary<int, System.Reflection.Assembly> _assemblyCache = new Dictionary<int, System.Reflection.Assembly>();
        private static object _compilerlock = new object();//编译锁,同时只有一个实例编译

        public Type Compiler(List<string> referencedAssemblies, string typename, string[] code)
        {

            Assembly objAssembly = null;
            if (_assemblyCache.ContainsKey(code.GetHashCode()))
            {
                objAssembly = _assemblyCache[code.GetHashCode()];
            }

            lock (_compilerlock)
            {
                // 1.CodeDomProvider
                CodeDomProvider objICodeCompiler = CodeDomProvider.CreateProvider("CSharp");

                // 2.CompilerParameters
                CompilerParameters objCompilerParameters = new CompilerParameters();
                objCompilerParameters.ReferencedAssemblies.Add("System.dll");
                foreach (var r in referencedAssemblies)
                {
                    string referencedpath = r;
                    if (r.IndexOf("\\") <= 0)
                    {
                        referencedpath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase).Substring(6).Trim('\\') + "\\" + r;
                    }
                    objCompilerParameters.ReferencedAssemblies.Add(referencedpath);
                }
                objCompilerParameters.GenerateExecutable = false;
                objCompilerParameters.GenerateInMemory = false;

                // 3.CompilerResults
                CompilerResults cr = objICodeCompiler.CompileAssemblyFromSource(objCompilerParameters, code);

                if (cr.Errors.HasErrors)
                {
                    string errors = "";
                    foreach (CompilerError err in cr.Errors)
                    {
                        errors += err.ErrorText;
                    }
                    if (!string.IsNullOrWhiteSpace(errors))
                    {
                        throw new ServiceCenterException("服务编译出错,可能是服务与接口不一致导致。编译错误信息:" + errors);
                    }
                }
                else
                {
                    objAssembly = cr.CompiledAssembly;
                    _assemblyCache.Add(code.GetHashCode(), objAssembly);
                    //object objHelloWorld = objAssembly.CreateInstance("DynamicCodeGenerate.HelloWorld");
                    //MethodInfo objMI = objHelloWorld.GetType().GetMethod("OutPut");

                    //Console.WriteLine(objMI.Invoke(objHelloWorld, null));
                }
            }
            return objAssembly.GetType(typename);
        }
    }
}
